home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 October: Mac OS SDK / Dev.CD Oct 00 SDK1.toast / Development Kits / Mac OS / Multiprocessing 2.1v2 SDK / Sample Code / MP Sort Picts 12⁄04⁄99 / Sprocket / Lib / DialogUtils.cp < prev    next >
Encoding:
Text File  |  1999-11-29  |  10.1 KB  |  386 lines  |  [TEXT/CWIE]

  1. /*
  2.     File:        DialogUtils.cp
  3.  
  4.     Contains:    Auto-sized error alert mechanism,
  5.                 ModalFilterProcs which correctly handle events,
  6.                 and Standard “Close Document” dialogs. 
  7.  
  8.     Written by: Dave Falkenburg
  9.  
  10.     Copyright:    © 1993-94 by Dave Falkenburg, all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.      
  14.          <5>    11/16/94    DRF        Added explicit #include <SegLoad.h> for latest universal
  15.                                     headers. Also added cast to keep MPW CFront happier.
  16.          <4>    11/16/94    DRF        Add StdFilterProc for THINK C.
  17.          <3>     9/27/94    DRF         AppLib.h is now Sprocket.h
  18.          <2>      9/9/94    DRF        Reordered headers and removed redundant #includes.
  19.  */
  20.  
  21. #include "Sprocket.h"
  22. extern pascal void ExitToShell(void );
  23.  
  24. #include <Fonts.h>
  25. #include <Resources.h>
  26. #include <TextUtils.h>
  27. #include <Threads.h>        //    For YieldToAnyThread()
  28. #include <StandardFile.h>    //    For ModalFilterYDProcPtr
  29. #include <SegLoad.h>        //    For ExitToShell()
  30. #include <Controls.h>
  31. #include <ControlDefinitions.h>
  32.  
  33. //    Some types which should probably be defined in <Dialogs.h>
  34. //    NOTE: These must be aligned on 2-byte boundaries
  35. #if defined(powerc) || defined (__powerc)
  36. #pragma options align=mac68k
  37. #endif
  38.  
  39. struct DialogItem
  40.     {
  41.     long    usedByDialogManager;
  42.     Rect    boundsRect;
  43.     char    type;
  44.     char    length;
  45.     };
  46.  
  47. struct DialogItemList            //    a.k.a. a 'DITL'
  48.     {
  49.     short        count;
  50.     DialogItem    firstItem[1];
  51.     };
  52.  
  53. //    Restore default alignment
  54. #if defined(powerc) || defined(__powerc)
  55. #pragma options align=reset
  56. #endif
  57.  
  58. typedef    DialogItem        *DialogItemPtr;
  59. typedef    DialogItemList    **DialogItemListHandle;
  60. typedef    DialogTemplate    **DialogTemplateHandle;
  61.  
  62. #ifndef    powerc
  63. #ifdef    __SC__
  64.  
  65. extern pascal OSErr GetStdFilterProc(ModalFilterUPP *theProc)
  66.  THREEWORDINLINE(0x303C, 0x0203, 0xAA68);
  67.  
  68. pascal Boolean
  69. StdFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  70.     {
  71.     ModalFilterUPP    filterUPP;
  72.  
  73.     //    Dialogs.h
  74.     
  75.     (void) GetStdFilterProc(&filterUPP);
  76.  
  77.     return    CallModalFilterProc(filterUPP,theDialog,anEvent,itemHit);
  78.     }
  79.  
  80. #endif
  81. #endif
  82.  
  83. //    private function Prototypes
  84.  
  85. static    pascal Boolean    StandardDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  86. static    pascal Boolean    StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit, void * yourData);
  87. static    pascal Boolean    StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  88. static    Boolean            FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * itemHit);
  89.  
  90.  
  91.  
  92. ///////////////////////////////////////////////////////////
  93. //
  94. //    StandardAlert
  95. //
  96. //    An alternative to Alert() which uses the extended
  97. //    Dialog Manager capabilities.
  98. //
  99. //    I’m not sure we really need this call, but it seems
  100. //    to do the trick just fine.
  101.  
  102. short
  103. StandardAlert(    short dlogID,
  104.                 short defaultItem,                /* = ok */
  105.                 short cancelItem,                /* = 0 */
  106.                 ModalFilterUPP customFilterProc    /* = nil */)
  107.     {
  108.     DialogPtr        theDialog;
  109.     short            itemHit = 0;
  110.     ModalFilterUPP    filterToUse;
  111.     
  112.     HiliteWindowsForModalDialog(false);
  113.  
  114.     theDialog = GetNewDialog(dlogID,nil,(WindowPtr) -1);
  115.     if (defaultItem)
  116.         SetDialogDefaultItem(theDialog,defaultItem);
  117.     if (cancelItem)
  118.         SetDialogCancelItem(theDialog,cancelItem);
  119.  
  120.     if (customFilterProc)
  121.         filterToUse = customFilterProc;
  122.     else
  123.         filterToUse = StandardDialogFilter;
  124.  
  125.     do
  126.         ModalDialog(filterToUse,&itemHit);
  127.     while (itemHit == 0);
  128.     
  129.     DisposeDialog(theDialog);
  130.  
  131.     HiliteWindowsForModalDialog(true);
  132.  
  133.     return itemHit;
  134.     }
  135.  
  136.  
  137. ///////////////////////////////////////////////////////////
  138. //
  139. //    ErrorAlert
  140. //
  141. //    A nice error reporting routine which presents an
  142. //    auto-sized alert box containing the supplied text.
  143. //
  144. //    NOTE:    This routine ASSUMES the following 'DITL'
  145. //            structure:
  146. //
  147. //            item #1 : an “OK” button
  148. //            item #2 : a static text item, somewhere above #1
  149. //
  150. //    NOTE:    We probably need to worry more about low
  151. //            memory conditions-- this can probably
  152. //            be handled by a custom GrowZoneProc and
  153. //            reserve memory area large enough to hold
  154. //            all the space we’d need.
  155. //
  156.  
  157. void
  158. ErrorAlert(short stringList,short whichString)
  159.     {
  160.     Str255                    errorString;
  161.     GrafPtr                    oldPort,windowMgrPort;
  162.     short                    oldFont;
  163.     DialogTemplateHandle    errorDialogTemplate;
  164.     DialogItemListHandle    errorDialogItems;
  165.     TEHandle                aTEHandle;
  166.     Rect                    textRect;
  167.     short                    textHeight;
  168.     short                    additionalSpaceNeeded;
  169.     DialogItemPtr            okButtonItem,errorTextItem;
  170.     const StringPtr            nullStr = (StringPtr) "\p";
  171.  
  172.     GetIndString(errorString,stringList,whichString);
  173.     
  174.     errorDialogTemplate = (DialogTemplateHandle) Get1Resource('DLOG',kErrorAlertID);
  175.     HLock((Handle) errorDialogTemplate);
  176.     
  177.     errorDialogItems = (DialogItemListHandle) Get1Resource('DITL',(**errorDialogTemplate).itemsID);
  178.     HLock((Handle) errorDialogItems);
  179.     
  180.     //    Find the dialog items
  181.     
  182.     okButtonItem = (**errorDialogItems).firstItem;
  183.     errorTextItem = (DialogItemPtr) ((Ptr) okButtonItem + sizeof(DialogItem) + okButtonItem->length);
  184.     
  185.     GetPort(&oldPort);
  186.     GetWMgrPort(&windowMgrPort);
  187.     SetPort(windowMgrPort);
  188.     oldFont = qd.thePort->txFont;
  189.     TextFont(systemFont);
  190.  
  191.     aTEHandle = TENew(&textRect,&textRect);
  192.     TESetText(&errorString[1],errorString[0],aTEHandle);
  193.     textHeight = (*aTEHandle)->lineHeight * (*aTEHandle)->nLines;
  194.     TEDispose(aTEHandle);
  195.  
  196.     additionalSpaceNeeded = textHeight - (errorTextItem->boundsRect.bottom
  197.                             - errorTextItem->boundsRect.top);
  198.  
  199.     if (additionalSpaceNeeded > 0)
  200.         {
  201.         (**errorDialogTemplate).boundsRect.bottom += additionalSpaceNeeded;
  202.         errorTextItem->boundsRect.bottom += additionalSpaceNeeded;
  203.         OffsetRect(&okButtonItem->boundsRect,0,additionalSpaceNeeded);
  204.         }
  205.         
  206.     TextFont(oldFont);
  207.     SetPort(oldPort);
  208.     
  209.     InitCursor();
  210.     ParamText(errorString,nullStr,nullStr,nullStr);
  211.  
  212.     (void) StandardAlert(kErrorAlertID);
  213.  
  214.     ReleaseResource((Handle) errorDialogTemplate);
  215.     ReleaseResource((Handle) errorDialogItems);
  216.     }
  217.  
  218.  
  219. ///////////////////////////////////////////////////////////
  220. //
  221. //    FatalErrorAlert
  222. //
  223. //    A companion to ErrorAlert which also kills the process.
  224. //
  225.  
  226. void
  227. FatalErrorAlert(short stringList,short whichString)
  228.     {
  229.     ErrorAlert(stringList,whichString);
  230.     ExitToShell();
  231.     }
  232.  
  233.  
  234. ///////////////////////////////////////////////////////////
  235. //
  236. //    StandardDialogFilter and StandardDialogFilterYD
  237. //
  238. //    These function takes care of routing events not meant
  239. //    for the dialog window to other parts of the application.
  240. //
  241. //    Use them as an alternative to passing a NIL ModalFilterProc
  242. //    to ModalDialog() and CustomGet(Put)File. Unlike the default
  243. //    filter, these routines properly processes update events
  244. //    to keep background processes running.
  245. //
  246. //    The Thread Manager, if present, is also called to yield
  247. //    control to other cooperative threads within the process.
  248. //
  249. //    Because of pascal calling conventions we need two separate
  250. //    routines, but this is minimized by sharing implementation
  251. //    in FilterProcCommon.
  252. //
  253.  
  254. ModalFilterUPP    StandardDialogFilter
  255. = NewModalFilterProc(StandardDialogFilterProc);
  256.  
  257. ModalFilterYDUPP    StandardDialogFilterYD
  258. = NewModalFilterYDProc(StandardDialogFilterYDProc);
  259.  
  260. ModalFilterUPP    StandardCloseDialogFilter
  261. = NewModalFilterProc(StandardCloseDialogFilterProc);
  262.  
  263.  
  264. pascal Boolean
  265. StandardDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  266.     {
  267.     //    Call through common code to check for events we’d like to handle.
  268.     //    If that is unsuccessful, call through the System 7 StdFilterProc
  269.     //    to handle CR, “CMD-.” & ESC in an international-friendly manner.
  270.  
  271.     if (FilterProcCommon(theDialog, anEvent, itemHit))
  272.         return true;
  273.     else
  274.         return (StdFilterProc(theDialog, anEvent, itemHit));
  275.     }
  276.  
  277.  
  278. pascal Boolean
  279. StandardDialogFilterYDProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit, void * /*unusedData*/)
  280.     {
  281.     //    We don’t call through to StdFilterProc since the
  282.     //    Standard File Package already does everything we need.
  283.  
  284.     return FilterProcCommon(theDialog, anEvent, itemHit);
  285.     }
  286.  
  287. void
  288. PseudoClickInDialogItem(DialogPtr theDialog, short itemToClick)
  289.     {
  290.     Handle    itemHandle;
  291.     Rect    itemBox;
  292.     UInt32    finalTicks;
  293.     short    itemType;
  294.     
  295.     GetDialogItem(theDialog,itemToClick,&itemType,&itemHandle,&itemBox);
  296.  
  297.     HiliteControl((ControlHandle) itemHandle, kControlButtonPart);
  298.     Delay(8,&finalTicks);
  299.     HiliteControl((ControlHandle) itemHandle,0);
  300.     }
  301.  
  302.  
  303. pascal Boolean
  304. StandardCloseDialogFilterProc(DialogPtr theDialog, EventRecord* anEvent, short* itemHit)
  305.     {
  306.     if ((anEvent->what == keyDown))
  307.         {
  308.         char    c = (char) anEvent->message & charCodeMask;
  309.         
  310.         if ((c == 'd') || (c == 'D'))                //    NOT INTERNATIONAL FRIENDLY!!!
  311.             {
  312.             *itemHit = kDontSaveDocument;
  313.             PseudoClickInDialogItem(theDialog,kDontSaveDocument);
  314.             return true;
  315.             }
  316.         }
  317.  
  318.     //    Return through the common code above so that default item processing can happen
  319.     return StandardDialogFilterProc(theDialog, anEvent, itemHit);
  320.     }
  321.  
  322.  
  323. Boolean
  324. FilterProcCommon(DialogPtr theDialog, EventRecord * anEvent, short * /* itemHit */)
  325.     {
  326.     switch (anEvent->what)
  327.         {
  328.         case updateEvt:
  329.         case activateEvt:
  330.             //     Update or activate for the dialog window?
  331.             if (theDialog == (DialogPtr) anEvent->message)
  332.                 break;
  333.  
  334.             //    no, fall through to HandleEvent            
  335.             
  336.         case diskEvt:
  337.             HandleEvent(anEvent);
  338.             return(false);
  339.  
  340.         default:
  341.             break;        
  342.         }
  343.  
  344.     if (gHasThreadManager)        //    If we have threads, let them run!
  345.         YieldToAnyThread();
  346.  
  347.     return false;                //    We didn’t handle the event
  348.     }
  349.  
  350.  
  351. //////////////////////////////////////////////////////////////////
  352. //
  353. //    StandardCloseDocument
  354. //
  355. //    Provides the standard human interface for closing a document
  356. //
  357. //    NOTE: When we make TDocument class, this will become a method
  358. //          and probably won’t need any parameters.
  359. //
  360. //    NOTE:    StandardCloseResult matches the dialog items for 
  361.  
  362. StandardCloseResult
  363. StandardCloseDocument(const StringPtr documentType, StringPtr documentName,
  364.                       Boolean hasNewEditions, Boolean quitting)
  365.     {
  366.     short        whichAlert;
  367.     short        whichString;
  368.     StringPtr    nullStr = (StringPtr) "\p";
  369.     Str255        reasonForClosingStr;
  370.  
  371.     if (hasNewEditions)
  372.         whichAlert = kStandardCloseWithNewPubsAlertID;
  373.     else
  374.         whichAlert = kStandardCloseAlertID;
  375.     
  376.     if (quitting)
  377.         whichString = kQuittingStr;
  378.     else
  379.         whichString = kClosingStr;
  380.  
  381.     GetIndString(reasonForClosingStr,kStandardCloseStrings,whichString);
  382.     ParamText(documentType,documentName,reasonForClosingStr,nullStr);
  383.     
  384.     return ((StandardCloseResult) StandardAlert(whichAlert,kSaveDocument,kCancelSaveDocument,StandardCloseDialogFilter));
  385.     }
  386.